package com.joysuch.wwyt.dynamicdata.processor;


import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.google.common.collect.Maps;
import com.joysuch.wwyt.core.common.util.JsonUtil;
import com.joysuch.wwyt.dynamicdata.DynamicBean;
import com.joysuch.wwyt.dynamicdata.DynamicDataConstants;
import com.joysuch.wwyt.dynamicdata.entity.BaseDynamicData;
import com.joysuch.wwyt.dynamicdata.entity.BaseDynamicFieldConfig;
import com.joysuch.wwyt.dynamicdata.entity.BatchSaveTuple;
import org.apache.commons.beanutils.PropertyUtilsBean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.util.*;

/**
 * <p>
 * 动态数据处理基础类
 * </p>
 *
 * @author jwk
 * @since 2021-11-30
 */
public abstract class AbstractDynamicDataProcessor {

    private static final Logger logger = LoggerFactory.getLogger(AbstractDynamicDataProcessor.class);

    protected BatchSaveTuple saveDynamicData(Object obj, List<BaseDynamicFieldConfig> fieldConfigList) {
        List<BaseDynamicData> dataList = new ArrayList<>();
        Set<Long> bizIds = new HashSet<>();
        fieldConfigList.forEach(each -> {
            JSONArray dataArray = JSONUtil.parseArray(obj, false);
            for (Object data : dataArray) {
                Object dataObj = parseData(data);
                Long bizId = parseBizId(data);
                JSONArray fieldArray = JSONUtil.parseArray(dataObj, false);
                JSONObject fieldObject = parseValueJsonOfField(each.getFieldName(), fieldArray);
                if (fieldObject != null) {
                    Object fieldValue = fieldObject.get(each.getFieldName());
                    BaseDynamicData baseDynamicData = BaseDynamicData.builder().fieldConfigId(each.getId()).
                            bizId(bizId).
                            fieldName(each.getFieldName()).
                            dataType(each.getDataType()).
                            fieldValue(fieldValue != null ? fieldValue.toString() : null).
                            build();
                    dataList.add(baseDynamicData);
                    bizIds.add(bizId);
                }
            }
        });
        return BatchSaveTuple.builder().dataList(dataList).bizIds(bizIds).build();
    }

    protected Object addTargetField(Object dest, Map<String, Object> addProperties) {
        PropertyUtilsBean propertyUtilsBean = new PropertyUtilsBean();
        PropertyDescriptor[] descriptors = propertyUtilsBean.getPropertyDescriptors(dest);
        Map<String, Class<?>> propertyMap = Maps.newHashMap();
        for (PropertyDescriptor descriptor : descriptors) {
            String descriptorName = descriptor.getName();
            if (!DynamicDataConstants.FILTER_ELEMENT.contains(descriptorName)) {
                propertyMap.put(descriptor.getName(), descriptor.getPropertyType());
            }
        }
        addProperties.forEach((k, v) -> propertyMap.put(k, v.getClass()));
        DynamicBean dynamicBean = new DynamicBean(dest.getClass(), propertyMap);
        propertyMap.forEach((k, v) -> {
            // filter extra properties
            if (!addProperties.containsKey(k)) {
                try {
                    Object object = propertyUtilsBean.getNestedProperty(dest, k);
                    dynamicBean.setValue(k, object);
                } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
                    logger.error("getTarget >> getNestedProperty error", e);
                }
            }
        });
        addProperties.forEach(dynamicBean::setValue);
        return dynamicBean.getTarget();
    }

    protected JSONObject parseValueJsonOfField(String fieldName, JSONArray jsonArray) {
        for (Object json : jsonArray) {
            if (JSONUtil.isJsonObj(json.toString())) {
                JSONObject jsonData = JSONUtil.parseObj(json);
                if (jsonData.containsKey(fieldName)) {
                    return jsonData;
                }
            }
        }
        return null;
    }

    protected Object parseData(Object obj) {
        JSONObject jsonObject = JSONUtil.parseObj(obj);
        return jsonObject.get(DynamicDataConstants.DATA);
    }

    protected Long parseBizId(Object obj) {
        JSONObject jsonObject = JSONUtil.parseObj(obj);
        Object bizObj = jsonObject.get(DynamicDataConstants.BIZ_ID);
        if (bizObj instanceof Number) {
            return Long.valueOf(bizObj.toString());
        } else {
            logger.error("parseBizId error param:{}", JsonUtil.toJson(obj));
            throw new IllegalArgumentException("bizObj is not of type Long");
        }
    }
}
